home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Online / x3270 / unix_files / CmplxMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-10-18  |  39.7 KB  |  1,376 lines

  1. /* (from) $XConsortium: SimpleMenu.c,v 1.41 92/09/10 16:25:07 converse Exp $ */
  2.  
  3. /*
  4.  * Modifications Copyright 1995, 1999 by Paul Mattes.
  5.  *  Permission to use, copy, modify, and distribute this software and its
  6.  *  documentation for any purpose and without fee is hereby granted,
  7.  *  provided that the above copyright notice appear in all copies and that
  8.  *  both that copyright notice and this permission notice appear in
  9.  *  supporting documentation.
  10.  *
  11.  * Copyright 1989 Massachusetts Institute of Technology
  12.  *
  13.  * Permission to use, copy, modify, distribute, and sell this software and its
  14.  * documentation for any purpose is hereby granted without fee, provided that
  15.  * the above copyright notice appear in all copies and that both that
  16.  * copyright notice and this permission notice appear in supporting
  17.  * documentation, and that the name of M.I.T. not be used in advertising or
  18.  * publicity pertaining to distribution of the software without specific,
  19.  * written prior permission.  M.I.T. makes no representations about the
  20.  * suitability of this software for any purpose.  It is provided "as is"
  21.  * without express or implied warranty.
  22.  *
  23.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  25.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  26.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  27.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  28.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  29.  */
  30.  
  31. /*
  32.  * ComplexMenu.c - Source code file for ComplexMenu widget.
  33.  * (from) SimpleMenu.c - Source code file for SimpleMenu widget.
  34.  *
  35.  * Date:    April 3, 1989
  36.  *
  37.  * By:      Chris D. Peterson
  38.  *          MIT X Consortium 
  39.  *          kit@expo.lcs.mit.edu
  40.  */
  41.  
  42. #include "globals.h"
  43. #if defined(X3270_MENUS) /*[*/
  44.  
  45. #include <stdio.h>
  46. #include <X11/IntrinsicP.h>
  47. #include <X11/StringDefs.h>
  48.  
  49. #include <X11/Xaw/XawInit.h>
  50. #include "CmplxMenuP.h"
  51. #include "CmeBSB.h"
  52. #include <X11/Xaw/Cardinals.h>
  53. #include <X11/Xaw/MenuButton.h>
  54.  
  55. #include <X11/Xmu/Initer.h>
  56. #include <X11/Xmu/CharSet.h>
  57.  
  58. #define streq(a, b)        ( strcmp((a), (b)) == 0 )
  59.  
  60. #define offset(field) XtOffsetOf(ComplexMenuRec, complex_menu.field)
  61.  
  62. static XtResource resources[] = { 
  63.  
  64. /*
  65.  * Label Resources.
  66.  */
  67.  
  68.   {XtNlabel,  XtCLabel, XtRString, sizeof(String),
  69.      offset(label_string), XtRString, NULL},
  70.   {XtNlabelClass,  XtCLabelClass, XtRPointer, sizeof(WidgetClass),
  71.      offset(label_class), XtRImmediate, (XtPointer) NULL},
  72.  
  73. /*
  74.  * Layout Resources.
  75.  */
  76.  
  77.   {XtNrowHeight,  XtCRowHeight, XtRDimension, sizeof(Dimension),
  78.      offset(row_height), XtRImmediate, (XtPointer) 0},
  79.   {XtNtopMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  80.      offset(top_margin), XtRImmediate, (XtPointer) 0},
  81.   {XtNbottomMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  82.      offset(bottom_margin), XtRImmediate, (XtPointer) 0},
  83.  
  84. /*
  85.  * Misc. Resources
  86.  */
  87.  
  88.   { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
  89.       XtOffsetOf(ComplexMenuRec, shell.allow_shell_resize),
  90.       XtRImmediate, (XtPointer) TRUE },
  91.   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  92.       offset(cursor), XtRImmediate, (XtPointer) None},
  93.   {XtNmenuOnScreen,  XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
  94.       offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
  95.   {XtNpopupOnEntry,  XtCPopupOnEntry, XtRWidget, sizeof(Widget),
  96.       offset(popup_entry), XtRWidget, NULL},
  97.   {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
  98.       offset(backing_store), 
  99.       XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
  100.   {XtNcMparent, XtCCMparent, XtRWidget, sizeof(Widget),
  101.       offset(parent), XtRWidget, NULL},
  102.   {XtNcMdefer, XtCCMdefer, XtRWidget, sizeof(Widget),
  103.       offset(deferred_notify), XtRWidget, NULL},
  104. };  
  105. #undef offset
  106.  
  107. static char defaultTranslations[] =
  108.     "<EnterWindow>:     highlight()             \n\
  109.      <LeaveWindow>:     leftWindow()            \n\
  110.      <BtnMotion>:       highlight()             \n\
  111.      <BtnUp>:           saveUnhighlight() MenuPopdown()"; 
  112.  
  113. /*
  114.  * Semi Public function definitions. 
  115.  */
  116.  
  117. static void Redisplay(Widget, XEvent *, Region);
  118. static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
  119. static void ChangeManaged(Widget);
  120. static void Resize(Widget);
  121. static void Initialize(Widget, Widget, ArgList, Cardinal *);
  122. static void ClassInitialize(void);
  123. static void ClassPartInitialize(WidgetClass);
  124. static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
  125. static Boolean SetValuesHook(Widget, ArgList, Cardinal *);
  126. static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
  127.     XtWidgetGeometry *);
  128.  
  129. /*
  130.  * Action Routine Definitions
  131.  */
  132.  
  133. static void PositionMenuAction(Widget, XEvent *, String *, Cardinal *);
  134. static void SaveUnhighlight(Widget, XEvent *, String *, Cardinal *);
  135. static void LeftWindow(Widget, XEvent *, String *, Cardinal *);
  136. static void Highlight(Widget, XEvent *, String *, Cardinal *);
  137.  
  138. /* 
  139.  * Private Function Definitions.
  140.  */
  141.  
  142. static void Unhighlight(), Notify();
  143. static void MakeSetValuesRequest(Widget, Dimension, Dimension);
  144. static void Layout(Widget, Dimension *, Dimension *);
  145. static void CreateLabel(Widget);
  146. static void AddPositionAction(XtAppContext, caddr_t);
  147. static void ChangeCursorOnGrab(Widget, XtPointer junk, XtPointer);
  148. static void PositionMenu(Widget, XPoint *);
  149. static void ClearParent(Widget, XtPointer, XtPointer);
  150. static Dimension GetMenuWidth(Widget, Widget);
  151. static Dimension GetMenuHeight(Widget);
  152. static Widget FindMenu(Widget, String);
  153. static CmeObject GetEventEntry(Widget, XEvent *);
  154. static CmeObject GetRightEntry(Widget, XEvent *);
  155. static void MoveMenu(Widget, Position, Position);
  156.  
  157. static XtActionsRec actionsList[] =
  158. {
  159.   {"highlight",         Highlight},
  160.   {"saveUnhighlight",   SaveUnhighlight},
  161.   {"leftWindow",    LeftWindow},
  162. };
  163.  
  164. static CompositeClassExtensionRec extension_rec = {
  165.     /* next_extension */  NULL,
  166.     /* record_type */     NULLQUARK,
  167.     /* version */         XtCompositeExtensionVersion,
  168.     /* record_size */     sizeof(CompositeClassExtensionRec),
  169.     /* accepts_objects */ TRUE,
  170. };
  171.  
  172. #define superclass (&overrideShellClassRec)
  173.     
  174. ComplexMenuClassRec complexMenuClassRec = {
  175.   {
  176.     /* superclass         */    (WidgetClass) superclass,
  177.     /* class_name         */    "ComplexMenu",
  178.     /* size               */    sizeof(ComplexMenuRec),
  179.     /* class_initialize   */    ClassInitialize,
  180.     /* class_part_initialize*/    ClassPartInitialize,
  181.     /* Class init'ed      */    FALSE,
  182.     /* initialize         */    Initialize,
  183.     /* initialize_hook    */    NULL,
  184.     /* realize            */    Realize,
  185.     /* actions            */    actionsList,
  186.     /* num_actions        */    XtNumber(actionsList),
  187.     /* resources          */    resources,
  188.     /* resource_count     */    XtNumber(resources),
  189.     /* xrm_class          */    NULLQUARK,
  190.     /* compress_motion    */    TRUE, 
  191.     /* compress_exposure  */    TRUE,
  192.     /* compress_enterleave*/     TRUE,
  193.     /* visible_interest   */    FALSE,
  194.     /* destroy            */    NULL,
  195.     /* resize             */    Resize,
  196.     /* expose             */    Redisplay,
  197.     /* set_values         */    SetValues,
  198.     /* set_values_hook    */    SetValuesHook,
  199.     /* set_values_almost  */    XtInheritSetValuesAlmost,  
  200.     /* get_values_hook    */    NULL,            
  201.     /* accept_focus       */    NULL,
  202.     /* intrinsics version */    XtVersion,
  203.     /* callback offsets   */    NULL,
  204.     /* tm_table          */    defaultTranslations,
  205.     /* query_geometry      */    NULL,
  206.     /* display_accelerator*/    NULL,
  207.     /* extension      */    NULL
  208.   },{
  209.     /* geometry_manager   */    GeometryManager,
  210.     /* change_managed     */    ChangeManaged,
  211.     /* insert_child      */    XtInheritInsertChild,
  212.     /* delete_child      */    XtInheritDeleteChild,
  213.     /* extension      */    NULL
  214.   },{
  215.     /* Shell extension      */    NULL
  216.   },{
  217.     /* Override extension */    NULL
  218.   },{
  219.     /* Complex Menu extension*/  NULL
  220.   }
  221. };
  222.  
  223. WidgetClass complexMenuWidgetClass = (WidgetClass)&complexMenuClassRec;
  224.  
  225. /************************************************************
  226.  *
  227.  * Semi-Public Functions.
  228.  *
  229.  ************************************************************/
  230.  
  231. /*      Function Name: ClassInitialize
  232.  *      Description: Class Initialize routine, called only once.
  233.  *      Arguments: none.
  234.  *      Returns: none.
  235.  */
  236.  
  237. static void
  238. ClassInitialize(void)
  239. {
  240.   XawInitializeWidgetSet();
  241.   XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
  242.          NULL, 0 );
  243.   XmuAddInitializer( AddPositionAction, NULL);
  244. }
  245.  
  246. /*      Function Name: ClassInitialize
  247.  *      Description: Class Part Initialize routine, called for every
  248.  *                   subclass.  Makes sure that the subclasses pick up 
  249.  *                   the extension record.
  250.  *      Arguments: wc - the widget class of the subclass.
  251.  *      Returns: none.
  252.  */
  253.  
  254. static void
  255. ClassPartInitialize(WidgetClass wc)
  256. {
  257.     ComplexMenuWidgetClass cmwc = (ComplexMenuWidgetClass) wc;
  258.  
  259. /*
  260.  * Make sure that our subclass gets the extension rec too.
  261.  */
  262.  
  263.     extension_rec.next_extension = cmwc->composite_class.extension;
  264.     cmwc->composite_class.extension = (XtPointer) &extension_rec;
  265. }
  266.  
  267. /*      Function Name: Initialize
  268.  *      Description: Initializes the complex menu widget
  269.  *      Arguments: request - the widget requested by the argument list.
  270.  *                 new     - the new widget with both resource and non
  271.  *                           resource values.
  272.  *      Returns: none.
  273.  */
  274.  
  275. static void
  276. Initialize(Widget request unused, Widget new, ArgList args unused,
  277.     Cardinal *num_args unused)
  278. {
  279.   ComplexMenuWidget cmw = (ComplexMenuWidget) new;
  280.  
  281.   XmuCallInitializers(XtWidgetToApplicationContext(new));
  282.  
  283.   if (cmw->complex_menu.label_class == NULL) 
  284.       cmw->complex_menu.label_class = cmeBSBObjectClass;
  285.  
  286.   cmw->complex_menu.label = NULL;
  287.   cmw->complex_menu.entry_set = NULL;
  288.   cmw->complex_menu.prev_entry = NULL;
  289.   cmw->complex_menu.recursive_set_values = FALSE;
  290.  
  291.   if (cmw->complex_menu.label_string != NULL)
  292.       CreateLabel(new);
  293.  
  294.   cmw->complex_menu.menu_width = TRUE;
  295.  
  296.   if (cmw->core.width == 0) {
  297.       cmw->complex_menu.menu_width = FALSE;
  298.       cmw->core.width = GetMenuWidth(new, (Widget)NULL);
  299.   }
  300.  
  301.   cmw->complex_menu.menu_height = TRUE;
  302.  
  303.   if (cmw->core.height == 0) {
  304.       cmw->complex_menu.menu_height = FALSE;
  305.       cmw->core.height = GetMenuHeight(new);
  306.   }
  307.  
  308. /*
  309.  * Add a popup_callback routine for changing the cursor.
  310.  */
  311.   
  312.   XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
  313.  
  314. /*
  315.  * Add a popdown_callback routine for clearing the parent field.
  316.  */
  317.   
  318.   XtAddCallback(new, XtNpopdownCallback, ClearParent, NULL);
  319. }
  320.  
  321. /*      Function Name: Redisplay
  322.  *      Description: Redisplays the contents of the widget.
  323.  *      Arguments: w - the complex menu widget.
  324.  *                 event - the X event that caused this redisplay.
  325.  *                 region - the region the needs to be repainted. 
  326.  *      Returns: none.
  327.  */
  328.  
  329. static void
  330. Redisplay(Widget w, XEvent *event unused, Region region)
  331. {
  332.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  333.     CmeObject * entry;
  334.     CmeObjectClass class;
  335.  
  336.     if (region == NULL)
  337.     XClearWindow(XtDisplay(w), XtWindow(w));
  338.  
  339.     /*
  340.      * Check and Paint each of the entries - including the label.
  341.      */
  342.  
  343.     ForAllChildren(cmw, entry) {
  344.     if (!XtIsManaged ( (Widget) *entry)) continue;
  345.  
  346.     if (region != NULL) 
  347.         switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
  348.                  (int) (*entry)->rectangle.y,
  349.                  (unsigned int) (*entry)->rectangle.width,
  350.                  (unsigned int) (*entry)->rectangle.height)) {
  351.         case RectangleIn:
  352.         case RectanglePart:
  353.         break;
  354.         default:
  355.         continue;
  356.         }
  357.     class = (CmeObjectClass) (*entry)->object.widget_class;
  358.  
  359.     if (class->rect_class.expose != NULL)
  360.         (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
  361.     }
  362. }
  363.  
  364. /*      Function Name: Realize
  365.  *      Description: Realizes the widget.
  366.  *      Arguments: w - the complex menu widget.
  367.  *                 mask - value mask for the window to create.
  368.  *                 attrs - attributes for the window to create.
  369.  *      Returns: none
  370.  */
  371.  
  372. static void
  373. Realize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
  374. {
  375.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  376.  
  377.     attrs->cursor = cmw->complex_menu.cursor;
  378.     *mask |= CWCursor;
  379.     if ((cmw->complex_menu.backing_store == Always) ||
  380.     (cmw->complex_menu.backing_store == NotUseful) ||
  381.     (cmw->complex_menu.backing_store == WhenMapped) ) {
  382.     *mask |= CWBackingStore;
  383.     attrs->backing_store = cmw->complex_menu.backing_store;
  384.     }
  385.     else
  386.     *mask &= ~CWBackingStore;
  387.  
  388.     (*superclass->core_class.realize) (w, mask, attrs);
  389. }
  390.  
  391. /*      Function Name: Resize
  392.  *      Description: Handle the menu being resized bigger.
  393.  *      Arguments: w - the complex menu widget.
  394.  *      Returns: none.
  395.  */
  396.  
  397. static void
  398. Resize(Widget w)
  399. {
  400.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  401.     CmeObject * entry;
  402.  
  403.     if ( !XtIsRealized(w) ) return;
  404.  
  405.     ForAllChildren(cmw, entry)     /* reset width of all entries. */
  406.     if (XtIsManaged( (Widget) *entry))
  407.         (*entry)->rectangle.width = cmw->core.width;
  408.     
  409.     Redisplay(w, (XEvent *) NULL, (Region) NULL);
  410. }
  411.  
  412. /*      Function Name: SetValues
  413.  *      Description: Relayout the menu when one of the resources is changed.
  414.  *      Arguments: current - current state of the widget.
  415.  *                 request - what was requested.
  416.  *                 new - what the widget will become.
  417.  *      Returns: none
  418.  */
  419.  
  420. static Boolean
  421. SetValues(Widget current, Widget request unused, Widget new,
  422.     ArgList args unused, Cardinal *num_args unused)
  423. {
  424.     ComplexMenuWidget cmw_old = (ComplexMenuWidget) current;
  425.     ComplexMenuWidget cmw_new = (ComplexMenuWidget) new;
  426.     Boolean ret_val = FALSE, layout = FALSE;
  427.     
  428.     if (!XtIsRealized(current)) return(FALSE);
  429.     
  430.     if (!cmw_new->complex_menu.recursive_set_values) {
  431.     if (cmw_new->core.width != cmw_old->core.width) {
  432.         cmw_new->complex_menu.menu_width = (cmw_new->core.width != 0);
  433.         layout = TRUE;
  434.     }
  435.     if (cmw_new->core.height != cmw_old->core.height) {
  436.         cmw_new->complex_menu.menu_height = (cmw_new->core.height != 0);
  437.         layout = TRUE;
  438.     }
  439.     }
  440.  
  441.     if (cmw_old->complex_menu.cursor != cmw_new->complex_menu.cursor)
  442.     XDefineCursor(XtDisplay(new),
  443.               XtWindow(new), cmw_new->complex_menu.cursor);
  444.     
  445.     if (cmw_old->complex_menu.label_string !=cmw_new->complex_menu.label_string) { 
  446.     if (cmw_new->complex_menu.label_string == NULL)         /* Destroy. */
  447.         XtDestroyWidget((Widget) cmw_old->complex_menu.label);
  448.     else if (cmw_old->complex_menu.label_string == NULL)    /* Create. */
  449.         CreateLabel(new);
  450.     else {                                                 /* Change. */
  451.         Arg arglist[1];
  452.         
  453.         XtSetArg(arglist[0], XtNlabel, cmw_new->complex_menu.label_string);
  454.         XtSetValues((Widget) cmw_new->complex_menu.label, arglist, ONE);
  455.     }
  456.     }
  457.     
  458.     if (cmw_old->complex_menu.label_class != cmw_new->complex_menu.label_class)
  459.     XtAppWarning(XtWidgetToApplicationContext(new),
  460.              "No Dynamic class change of the ComplexMenu Label.");
  461.     
  462.     if ((cmw_old->complex_menu.top_margin != cmw_new->complex_menu.top_margin) ||
  463.     (cmw_old->complex_menu.bottom_margin != 
  464.      cmw_new->complex_menu.bottom_margin) /* filler.................  */ ) {
  465.     layout = TRUE;
  466.     ret_val = TRUE;
  467.     }
  468.  
  469.     if (layout)
  470.     Layout(new, (Dimension *)NULL, (Dimension *)NULL);
  471.  
  472.     return(ret_val);
  473. }
  474.  
  475. /*      Function Name: SetValuesHook
  476.  *      Description: To handle a special case, this is passed the
  477.  *                   actual arguments.
  478.  *      Arguments: w - the menu widget.
  479.  *                 arglist - the argument list passed to XtSetValues.
  480.  *                 num_args - the number of args.
  481.  *      Returns: none
  482.  */
  483.  
  484. /* 
  485.  * If the user actually passed a width and height to the widget
  486.  * then this MUST be used, rather than our newly calculated width and
  487.  * height.
  488.  */
  489.  
  490. static Boolean
  491. SetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
  492. {
  493.     register Cardinal i;
  494.     Dimension width, height;
  495.     
  496.     width = w->core.width;
  497.     height = w->core.height;
  498.     
  499.     for ( i = 0 ; i < *num_args ; i++) {
  500.     if ( streq(arglist[i].name, XtNwidth) )
  501.         width = (Dimension) arglist[i].value;
  502.     if ( streq(arglist[i].name, XtNheight) )
  503.         height = (Dimension) arglist[i].value;
  504.     }
  505.  
  506.     if ((width != w->core.width) || (height != w->core.height))
  507.     MakeSetValuesRequest(w, width, height);
  508.     return(FALSE);
  509. }
  510.  
  511. /************************************************************
  512.  *
  513.  * Geometry Management routines.
  514.  *
  515.  ************************************************************/
  516.  
  517. /*    Function Name: GeometryManager
  518.  *    Description: This is the ComplexMenu Widget's Geometry Manager.
  519.  *    Arguments: w - the Menu Entry making the request.
  520.  *                 request - requested new geometry.
  521.  *                 reply - the allowed geometry.
  522.  *    Returns: XtGeometry{Yes, No, Almost}.
  523.  */
  524.  
  525. static XtGeometryResult
  526. GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
  527. {
  528.     ComplexMenuWidget cmw = (ComplexMenuWidget) XtParent(w);
  529.     CmeObject entry = (CmeObject) w;
  530.     XtGeometryMask mode = request->request_mode;
  531.     XtGeometryResult answer;
  532.     Dimension old_height, old_width;
  533.  
  534.     if ( !(mode & CWWidth) && !(mode & CWHeight) )
  535.     return(XtGeometryNo);
  536.  
  537.     reply->width = request->width;
  538.     reply->height = request->height;
  539.  
  540.     old_width = entry->rectangle.width;
  541.     old_height = entry->rectangle.height;
  542.  
  543.     Layout(w, &(reply->width), &(reply->height) );
  544.  
  545. /*
  546.  * Since we are an override shell and have no parent there is no one to
  547.  * ask to see if this geom change is okay, so I am just going to assume
  548.  * we can do whatever we want.  If you subclass be very careful with this
  549.  * assumption, it could bite you.
  550.  *
  551.  * Chris D. Peterson - Sept. 1989.
  552.  */
  553.  
  554.     if ( (reply->width == request->width) &&
  555.      (reply->height == request->height) ) {
  556.  
  557.     if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
  558.         entry->rectangle.width = old_width;
  559.         entry->rectangle.height = old_height;    
  560.     }
  561.     else {
  562.         Layout(( Widget) cmw, (Dimension *)NULL, (Dimension *)NULL);
  563.     }
  564.     answer = XtGeometryDone;
  565.     }
  566.     else {
  567.     entry->rectangle.width = old_width;
  568.     entry->rectangle.height = old_height;    
  569.  
  570.     if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
  571.           ((reply->height == request->height) && !(mode & CWWidth)) ||
  572.           ((reply->width == request->width) && 
  573.            (reply->height == request->height)) )
  574.         answer = XtGeometryNo;
  575.     else {
  576.         answer = XtGeometryAlmost;
  577.         reply->request_mode = 0;
  578.         if (reply->width != request->width)
  579.         reply->request_mode |= CWWidth;
  580.         if (reply->height != request->height)
  581.         reply->request_mode |= CWHeight;
  582.     }
  583.     }
  584.     return(answer);
  585. }
  586.  
  587. /*    Function Name: ChangeManaged
  588.  *    Description: called whenever a new child is managed.
  589.  *    Arguments: w - the complex menu widget.
  590.  *    Returns: none.
  591.  */
  592.  
  593. static void
  594. ChangeManaged(Widget w)
  595. {
  596.     Layout(w, (Dimension *)NULL, (Dimension *)NULL);
  597. }
  598.  
  599. /************************************************************
  600.  *
  601.  * Global Action Routines.
  602.  * 
  603.  * These actions routines will be added to the application's
  604.  * global action list. 
  605.  * 
  606.  ************************************************************/
  607.  
  608. /*      Function Name: PositionMenuAction
  609.  *      Description: Positions the complex menu widget.
  610.  *      Arguments: w - a widget (no the complex menu widget.)
  611.  *                 event - the event that caused this action.
  612.  *                 params, num_params - parameters passed to the routine.
  613.  *                                      we expect the name of the menu here.
  614.  *      Returns: none
  615.  */
  616.  
  617. static void
  618. PositionMenuAction(Widget w, XEvent *event, String *params,
  619.     Cardinal *num_params)
  620.   Widget menu;
  621.   XPoint loc;
  622.  
  623.   if (*num_params != 1) {
  624.     char error_buf[BUFSIZ];
  625.     (void) sprintf(error_buf, "%s %s",
  626.         "Xaw - ComplexMenuWidget: position menu action expects only one",
  627.         "parameter which is the name of the menu.");
  628.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  629.     return;
  630.   }
  631.  
  632.   if ( (menu = FindMenu(w, params[0])) == NULL) {
  633.     char error_buf[BUFSIZ];
  634.     (void) sprintf(error_buf, "%s '%s'",
  635.         "Xaw - ComplexMenuWidget: could not find menu named: ", params[0]);
  636.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  637.     return;
  638.   }
  639.   
  640.   switch (event->type) {
  641.   case ButtonPress:
  642.   case ButtonRelease:
  643.     loc.x = event->xbutton.x_root;
  644.     loc.y = event->xbutton.y_root;
  645.     PositionMenu(menu, &loc);
  646.     break;
  647.   case EnterNotify:
  648.   case LeaveNotify:
  649.     loc.x = event->xcrossing.x_root;
  650.     loc.y = event->xcrossing.y_root;
  651.     PositionMenu(menu, &loc);
  652.     break;
  653.   case MotionNotify:
  654.     loc.x = event->xmotion.x_root;
  655.     loc.y = event->xmotion.y_root;
  656.     PositionMenu(menu, &loc);
  657.     break;
  658.   default:
  659.     PositionMenu(menu, (XPoint *)NULL);
  660.     break;
  661.   }
  662. }  
  663.  
  664. /************************************************************
  665.  *
  666.  * Widget Action Routines.
  667.  * 
  668.  ************************************************************/
  669.  
  670. /*      Function Name: Unhighlight
  671.  *      Description: Unhighlights current entry.
  672.  *      Arguments: w - the complex menu widget.
  673.  *                 event - the event that caused this action.
  674.  *                 params, num_params - ** NOT USED **
  675.  *      Returns: none
  676.  */
  677.  
  678. static void
  679. Unhighlight(Widget w, XEvent *event unused, String *params unused,
  680.     Cardinal *num_params unused)
  681.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  682.     CmeObject entry = cmw->complex_menu.entry_set;
  683.     CmeObjectClass class;
  684.  
  685.     if ( entry == NULL) return;
  686.  
  687.     cmw->complex_menu.entry_set = NULL;
  688.     class = (CmeObjectClass) entry->object.widget_class;
  689.     (class->cme_class.unhighlight) ( (Widget) entry);
  690. }
  691.  
  692. static void
  693. SaveUnhighlight(Widget w, XEvent *event unused, String *params unused,
  694.     Cardinal *num_params unused)
  695.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  696.     CmeObject entry = cmw->complex_menu.entry_set;
  697.     CmeObjectClass class;
  698.  
  699.     if ( entry == NULL) return;
  700.  
  701.     cmw->complex_menu.prev_entry = entry;
  702.     cmw->complex_menu.entry_set = NULL;
  703.     class = (CmeObjectClass) entry->object.widget_class;
  704.     (class->cme_class.unhighlight) ( (Widget) entry);
  705. }
  706.  
  707. /*      Function Name: LeftWindow
  708.  *      Description: Mouse has left window, usually this means unhighlight
  709.  *      Arguments: w - the complex menu widget.
  710.  *                 event - the event that caused this action.
  711.  *                 params, num_params - ** NOT USED **
  712.  *      Returns: none
  713.  */
  714.  
  715. static void
  716. LeftWindow(Widget w, XEvent *event, String *params unused,
  717.     Cardinal *num_params unused)
  718.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  719.     CmeObject entry = cmw->complex_menu.entry_set;
  720.     CmeObjectClass class;
  721.     String mn;
  722.  
  723.     if ( entry == NULL) return;
  724.  
  725.     mn = NULL;
  726.     XtVaGetValues((Widget) entry, XtNmenuName, &mn, NULL);
  727.     if (mn != NULL && GetRightEntry(w, event) == entry)
  728.     return;
  729.  
  730.     cmw->complex_menu.prev_entry = NULL;
  731.     cmw->complex_menu.entry_set = NULL;
  732.     class = (CmeObjectClass) entry->object.widget_class;
  733.     (class->cme_class.unhighlight) ( (Widget) entry);
  734. }
  735.  
  736. /*      Function Name: Highlight
  737.  *      Description: Highlights current entry.
  738.  *      Arguments: w - the complex menu widget.
  739.  *                 event - the event that caused this action.
  740.  *                 params, num_params - ** NOT USED **
  741.  *      Returns: none
  742.  */
  743.  
  744. static void
  745. Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
  746. {
  747.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  748.     CmeObject entry;
  749.     CmeObjectClass class;
  750.     ShellWidget shell_widget = (ShellWidget)w;
  751.  
  752.     
  753. #if defined(CmeDebug)
  754.     printf("Highlight(%x)\n", w);
  755. #endif
  756.  
  757.     if (shell_widget->shell.popped_up != TRUE) {
  758. #if defined(CmeDebug)
  759.     printf("bogus\n");
  760. #endif
  761.     return;
  762.     }
  763.  
  764.     if ( !XtIsSensitive(w) ) return;
  765.     
  766.     entry = GetEventEntry(w, event);
  767.  
  768.     if (entry == cmw->complex_menu.entry_set) return;
  769.  
  770.     Unhighlight(w, event, params, num_params);  
  771.  
  772.     if (entry == NULL) return;
  773.  
  774.     if ( !XtIsSensitive( (Widget) entry)) {
  775.     cmw->complex_menu.entry_set = NULL;
  776.     return;
  777.     }
  778.  
  779.     cmw->complex_menu.entry_set = entry;
  780.     class = (CmeObjectClass) entry->object.widget_class;
  781.  
  782.     (class->cme_class.highlight) ( (Widget) entry);
  783. }
  784.  
  785. /*      Function Name: Notify
  786.  *      Description: Notify user of current entry.
  787.  *      Arguments: w - the complex menu widget.
  788.  *                 event - the event that caused this action.
  789.  *                 params, num_params - ** NOT USED **
  790.  *      Returns: none
  791.  */
  792.  
  793. static void
  794. Notify(Widget w, XEvent *event unused, String *params unused,
  795.     Cardinal *num_params unused)
  796. {
  797.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  798.     CmeObject entry = cmw->complex_menu.entry_set;
  799.     CmeObjectClass class;
  800.     
  801.     if (entry == NULL)
  802.     entry = cmw->complex_menu.prev_entry;
  803.     if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
  804.  
  805.     if (cmw->complex_menu.parent != NULL) {
  806. #if defined(CmeDebug)
  807.     printf("Notify(%x): deferring to %x to parent %x\n", w, entry,
  808.         cmw->complex_menu.parent);
  809. #endif
  810.     XtVaSetValues(cmw->complex_menu.parent, XtNcMdefer, (Widget)entry,
  811.         NULL);
  812.     return;
  813.     }
  814. #if defined(CmeDebug)
  815.     else
  816.     printf("Notify(%x): not deferring\n", w);
  817. #endif
  818.     if (cmw->complex_menu.deferred_notify != NULL) {
  819. #if defined(CmeDebug)
  820.     printf("Notify: using deferred %x\n", w,
  821.         cmw->complex_menu.deferred_notify);
  822. #endif
  823.     entry = (CmeObject)cmw->complex_menu.deferred_notify;
  824.     }
  825.     class = (CmeObjectClass) entry->object.widget_class;
  826.     (class->cme_class.notify)( (Widget) entry );
  827. }
  828.  
  829. /************************************************************
  830.  *
  831.  * Public Functions.
  832.  *
  833.  ************************************************************/
  834.  
  835. /*    Function Name: XawComplexMenuAddGlobalActions
  836.  *    Description: adds the global actions to the complex menu widget.
  837.  *    Arguments: app_con - the appcontext.
  838.  *    Returns: none.
  839.  */
  840.  
  841. void
  842. XawComplexMenuAddGlobalActions(XtAppContext app_con)
  843. {
  844.     XtInitializeWidgetClass(complexMenuWidgetClass);
  845.     XmuCallInitializers( app_con );
  846.  
  847.  
  848. /*    Function Name: XawComplexMenuGetActiveEntry
  849.  *    Description: Gets the currently active (set) entry.
  850.  *    Arguments: w - the cmw widget.
  851.  *    Returns: the currently set entry or NULL if none is set.
  852.  */
  853.  
  854. Widget
  855. XawComplexMenuGetActiveEntry(Widget w)
  856. {
  857.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  858.  
  859.     return( (Widget) cmw->complex_menu.entry_set);
  860.  
  861. /*    Function Name: XawComplexMenuClearActiveEntry
  862.  *    Description: Unsets the currently active (set) entry.
  863.  *    Arguments: w - the cmw widget.
  864.  *    Returns: none.
  865.  */
  866.  
  867. void
  868. XawComplexMenuClearActiveEntry(Widget w)
  869. {
  870.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  871.  
  872.     cmw->complex_menu.entry_set = NULL;
  873.     cmw->complex_menu.prev_entry = NULL;
  874.  
  875. /************************************************************
  876.  *
  877.  * Private Functions.
  878.  *
  879.  ************************************************************/
  880.  
  881. /*    Function Name: CreateLabel
  882.  *    Description: Creates a the menu label.
  883.  *    Arguments: w - the cmw widget.
  884.  *    Returns: none.
  885.  * 
  886.  * Creates the label object and makes sure it is the first child in
  887.  * in the list.
  888.  */
  889.  
  890. static void
  891. CreateLabel(Widget w)
  892. {
  893.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  894.     register Widget * child, * next_child;
  895.     register int i;
  896.     Arg args[2];
  897.  
  898.     if ( (cmw->complex_menu.label_string == NULL) ||
  899.      (cmw->complex_menu.label != NULL) ) {
  900.     char error_buf[BUFSIZ];
  901.  
  902.     (void) sprintf(error_buf, "Xaw Complex Menu Widget: %s or %s, %s",
  903.         "label string is NULL", "label already exists", 
  904.         "no label is being created.");
  905.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  906.     return;
  907.     }
  908.  
  909.     XtSetArg(args[0], XtNlabel, cmw->complex_menu.label_string);
  910.     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
  911.     cmw->complex_menu.label = (CmeObject) 
  912.                           XtCreateManagedWidget("menuLabel", 
  913.                         cmw->complex_menu.label_class, w,
  914.                         args, TWO);
  915.  
  916.     next_child = NULL;
  917.     for (child = cmw->composite.children + cmw->composite.num_children,
  918.      i = cmw->composite.num_children ; i > 0 ; i--, child--) {
  919.     if (next_child != NULL)
  920.         *next_child = *child;
  921.     next_child = child;
  922.     }
  923.     *child = (Widget) cmw->complex_menu.label;
  924. }
  925.  
  926. /*    Function Name: Layout
  927.  *    Description: lays the menu entries out all nice and neat.
  928.  *    Arguments: w - See below (+++)
  929.  *                 width_ret, height_ret - The returned width and 
  930.  *                                         height values.
  931.  *    Returns: none.
  932.  *
  933.  * if width == NULL || height == NULL then it assumes the you do not care
  934.  * about the return values, and just want a relayout.
  935.  *
  936.  * if this is not the case then it will set width_ret and height_ret
  937.  * to be width and height that the child would get if it were layed out
  938.  * at this time.
  939.  *
  940.  * +++ "w" can be the complex menu widget or any of its object children.
  941.  */
  942.  
  943. static void
  944. Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
  945. {
  946.     CmeObject current_entry, *entry;
  947.     ComplexMenuWidget cmw;
  948.     Dimension width, height;
  949.     Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
  950.     Boolean allow_change_size;
  951.     height = 0;
  952.  
  953.     if ( XtIsSubclass(w, complexMenuWidgetClass) ) {
  954.     cmw = (ComplexMenuWidget) w;
  955.     current_entry = NULL;
  956.     }
  957.     else {
  958.     cmw = (ComplexMenuWidget) XtParent(w);
  959.     current_entry = (CmeObject) w;
  960.     }
  961.  
  962.     allow_change_size = (!XtIsRealized((Widget)cmw) ||
  963.              (cmw->shell.allow_shell_resize));
  964.  
  965.     if ( cmw->complex_menu.menu_height )
  966.     height = cmw->core.height;
  967.     else
  968.     if (do_layout) {
  969.         height = cmw->complex_menu.top_margin;
  970.         ForAllChildren(cmw, entry) {
  971.         if (!XtIsManaged( (Widget) *entry)) continue;
  972.  
  973.         if ( (cmw->complex_menu.row_height != 0) && 
  974.             (*entry != cmw->complex_menu.label) ) 
  975.             (*entry)->rectangle.height = cmw->complex_menu.row_height;
  976.         
  977.         (*entry)->rectangle.y = height;
  978.         (*entry)->rectangle.x = 0;
  979.         height += (*entry)->rectangle.height;
  980.         }
  981.         height += cmw->complex_menu.bottom_margin;
  982.     }
  983.     else {
  984.         if ((cmw->complex_menu.row_height != 0) && 
  985.         (current_entry != cmw->complex_menu.label) )
  986.         height = cmw->complex_menu.row_height;
  987.     }
  988.     
  989.     if (cmw->complex_menu.menu_width)
  990.     width = cmw->core.width;
  991.     else if ( allow_change_size )
  992.     width = GetMenuWidth((Widget) cmw, (Widget) current_entry);
  993.     else
  994.     width = cmw->core.width;
  995.  
  996.     if (do_layout) {
  997.     ForAllChildren(cmw, entry)
  998.         if (XtIsManaged( (Widget) *entry)) 
  999.         (*entry)->rectangle.width = width;
  1000.  
  1001.     if (allow_change_size)
  1002.         MakeSetValuesRequest((Widget) cmw, width, height);
  1003.     }
  1004.     else {
  1005.     *width_ret = width;
  1006.     if (height != 0)
  1007.         *height_ret = height;
  1008.     }
  1009. }
  1010.     
  1011. /*    Function Name: AddPositionAction
  1012.  *    Description: Adds the XawPositionComplexMenu action to the global
  1013.  *                   action list for this appcon.
  1014.  *    Arguments: app_con - the application context for this app.
  1015.  *                 data - NOT USED.
  1016.  *    Returns: none.
  1017.  */
  1018.  
  1019. static void
  1020. AddPositionAction(XtAppContext app_con, caddr_t data unused)
  1021. {
  1022.     static XtActionsRec pos_action[] = {
  1023.         { "XawPositionComplexMenu", PositionMenuAction },
  1024.     };
  1025.  
  1026.     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
  1027. }
  1028.  
  1029. /*    Function Name: FindMenu
  1030.  *    Description: Find the menu give a name and reference widget.
  1031.  *    Arguments: widget - reference widget.
  1032.  *                 name   - the menu widget's name.
  1033.  *    Returns: the menu widget or NULL.
  1034.  */
  1035.  
  1036. static Widget 
  1037. FindMenu(Widget widget, String name)
  1038. {
  1039.     register Widget w, menu;
  1040.     
  1041.     for ( w = widget ; w != NULL ; w = XtParent(w) )
  1042.     if ( (menu = XtNameToWidget(w, name)) != NULL )
  1043.         return(menu);
  1044.     return(NULL);
  1045. }
  1046.  
  1047. /*    Function Name: PositionMenu
  1048.  *    Description: Places the menu
  1049.  *    Arguments: w - the complex menu widget.
  1050.  *                 location - a pointer the the position or NULL.
  1051.  *    Returns: none.
  1052.  */
  1053.  
  1054. static void
  1055. PositionMenu(Widget w, XPoint *location)
  1056. {
  1057.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1058.     CmeObject entry;
  1059.     XPoint t_point;
  1060.     
  1061.     if (location == NULL) {
  1062.     Window junk1, junk2;
  1063.     int root_x, root_y, junkX, junkY;
  1064.     unsigned int junkM;
  1065.     
  1066.     location = &t_point;
  1067.     if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2, 
  1068.               &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
  1069.         char error_buf[BUFSIZ];
  1070.         (void) sprintf(error_buf, "%s %s", "Xaw - ComplexMenuWidget:",
  1071.             "Could not find location of mouse pointer");
  1072.         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  1073.         return;
  1074.     }
  1075.     location->x = (short) root_x;
  1076.     location->y = (short) root_y;
  1077.     }
  1078.     
  1079.     /*
  1080.      * The width will not be correct unless it is realized.
  1081.      */
  1082.     
  1083.     XtRealizeWidget(w);
  1084.     
  1085.     location->x -= (Position) w->core.width/2;
  1086.     
  1087.     if (cmw->complex_menu.popup_entry == NULL)
  1088.     entry = cmw->complex_menu.label;
  1089.     else
  1090.     entry = cmw->complex_menu.popup_entry;
  1091.  
  1092.     if (entry != NULL)
  1093.     location->y -= entry->rectangle.y + entry->rectangle.height/2;
  1094.  
  1095.     MoveMenu(w, (Position) location->x, (Position) location->y);
  1096. }
  1097.  
  1098. /*    Function Name: MoveMenu
  1099.  *    Description: Actually moves the menu, may force it to
  1100.  *                   to be fully visable if menu_on_screen is TRUE.
  1101.  *    Arguments: w - the complex menu widget.
  1102.  *                 x, y - the current location of the widget.
  1103.  *    Returns: none 
  1104.  */
  1105.  
  1106. static void
  1107. MoveMenu(Widget w, Position x, Position y)
  1108. {
  1109.     Arg arglist[2];
  1110.     Cardinal num_args = 0;
  1111.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1112.     
  1113.     if (cmw->complex_menu.menu_on_screen) {
  1114.     int width = w->core.width + 2 * w->core.border_width;
  1115.     int height = w->core.height + 2 * w->core.border_width;
  1116.     
  1117.     if (x >= 0) {
  1118.         int scr_width = WidthOfScreen(XtScreen(w));
  1119.         if (x + width > scr_width)
  1120.         x = scr_width - width;
  1121.     }
  1122.     if (x < 0) 
  1123.         x = 0;
  1124.     
  1125.     if (y >= 0) {
  1126.         int scr_height = HeightOfScreen(XtScreen(w));
  1127.         if (y + height > scr_height)
  1128.         y = scr_height - height;
  1129.     }
  1130.     if (y < 0)
  1131.         y = 0;
  1132.     }
  1133.     
  1134.     XtSetArg(arglist[num_args], XtNx, x); num_args++;
  1135.     XtSetArg(arglist[num_args], XtNy, y); num_args++;
  1136.     XtSetValues(w, arglist, num_args);
  1137. }
  1138.  
  1139. /*    Function Name: ChangeCursorOnGrab
  1140.  *    Description: Changes the cursor on the active grab to the one
  1141.  *                   specified in out resource list.
  1142.  *    Arguments: w - the widget.
  1143.  *                 junk, garbage - ** NOT USED **.
  1144.  *    Returns: None.
  1145.  */
  1146.  
  1147. static void
  1148. ChangeCursorOnGrab(Widget w, XtPointer junk unused, XtPointer garbage unused)
  1149. {
  1150.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1151.     
  1152. #if defined(CmeDebug)
  1153.     printf("ChangeCursorOnGrab(%x): parent=%x\n", w, cmw->complex_menu.parent);
  1154. #endif
  1155.     cmw->complex_menu.deferred_notify = NULL;
  1156.     cmw->complex_menu.prev_entry = NULL;
  1157.     
  1158.     /*
  1159.      * The event mask here is what is currently in the MIT implementation.
  1160.      * There really needs to be a way to get the value of the mask out
  1161.      * of the toolkit (CDP 5/26/89).
  1162.      */
  1163.     
  1164.     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
  1165.                  cmw->complex_menu.cursor, 
  1166.                  XtLastTimestampProcessed(XtDisplay(w)));
  1167. }
  1168.  
  1169. static void
  1170. ClearParent(Widget w, XtPointer junk unused, XtPointer garbage unused)
  1171. {
  1172.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1173.     
  1174. #if defined(CmeDebug)
  1175.     printf("ClearParent(%x): parent=%x\n", w, cmw->complex_menu.parent);
  1176. #endif
  1177.     Notify(w, (XEvent *)NULL, (String *)NULL, (Cardinal *)NULL);
  1178.     cmw->complex_menu.parent = NULL;
  1179. }
  1180.  
  1181. /*      Function Name: MakeSetValuesRequest
  1182.  *      Description: Makes a (possibly recursive) call to SetValues,
  1183.  *                   I take great pains to not go into an infinite loop.
  1184.  *      Arguments: w - the complex menu widget.
  1185.  *                 width, height - the size of the ask for.
  1186.  *      Returns: none
  1187.  */
  1188.  
  1189. static void
  1190. MakeSetValuesRequest(Widget w, Dimension width, Dimension height)
  1191. {
  1192.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1193.     Arg arglist[2];
  1194.     Cardinal num_args = (Cardinal) 0;
  1195.     
  1196.     if ( !cmw->complex_menu.recursive_set_values ) {
  1197.     if ( (cmw->core.width != width) || (cmw->core.height != height) ) {
  1198.         cmw->complex_menu.recursive_set_values = TRUE;
  1199.         XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
  1200.         XtSetArg(arglist[num_args], XtNheight, height); num_args++;
  1201.         XtSetValues(w, arglist, num_args);
  1202.     }
  1203.     else if (XtIsRealized( (Widget) cmw))
  1204.         Redisplay((Widget) cmw, (XEvent *) NULL, (Region) NULL);
  1205.     }
  1206.     cmw->complex_menu.recursive_set_values = FALSE;
  1207. }
  1208.  
  1209. /*      Function Name: GetMenuWidth
  1210.  *      Description: Sets the length of the widest entry in pixels.
  1211.  *      Arguments: w - the complex menu widget.
  1212.  *      Returns: width of menu.
  1213.  */
  1214.  
  1215. static Dimension
  1216. GetMenuWidth(Widget w, Widget w_ent)
  1217. {
  1218.     CmeObject cur_entry = (CmeObject) w_ent;
  1219.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1220.     Dimension width, widest = (Dimension) 0;
  1221.     CmeObject * entry;
  1222.     
  1223.     if ( cmw->complex_menu.menu_width ) 
  1224.     return(cmw->core.width);
  1225.  
  1226.     ForAllChildren(cmw, entry) {
  1227.     XtWidgetGeometry preferred;
  1228.  
  1229.     if (!XtIsManaged( (Widget) *entry)) continue;
  1230.     
  1231.     if (*entry != cur_entry) {
  1232.         XtQueryGeometry((Widget) *entry, NULL, &preferred);
  1233.         
  1234.         if (preferred.request_mode & CWWidth)
  1235.         width = preferred.width;
  1236.         else
  1237.         width = (*entry)->rectangle.width;
  1238.     }
  1239.     else
  1240.         width = (*entry)->rectangle.width;
  1241.     
  1242.     if ( width > widest )
  1243.         widest = width;
  1244.     }
  1245.     
  1246.     return(widest);
  1247. }
  1248.  
  1249. /*      Function Name: GetMenuHeight
  1250.  *      Description: Sets the length of the widest entry in pixels.
  1251.  *      Arguments: w - the complex menu widget.
  1252.  *      Returns: width of menu.
  1253.  */
  1254.  
  1255. static Dimension
  1256. GetMenuHeight(Widget w)
  1257. {
  1258.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1259.     CmeObject * entry;
  1260.     Dimension height;
  1261.     
  1262.     if (cmw->complex_menu.menu_height)
  1263.     return(cmw->core.height);
  1264.  
  1265.     height = cmw->complex_menu.top_margin + cmw->complex_menu.bottom_margin;
  1266.     
  1267.     if (cmw->complex_menu.row_height == 0) {
  1268.     ForAllChildren(cmw, entry) 
  1269.         if (XtIsManaged ((Widget) *entry)) 
  1270.         height += (*entry)->rectangle.height;
  1271.     } else 
  1272.     height += cmw->complex_menu.row_height * cmw->composite.num_children;
  1273.     
  1274.     return(height);
  1275. }
  1276.  
  1277. /*      Function Name: GetEventEntry
  1278.  *      Description: Gets an entry given an event that has X and Y coords.
  1279.  *      Arguments: w - the complex menu widget.
  1280.  *                 event - the event.
  1281.  *      Returns: the entry that this point is in.
  1282.  */
  1283.  
  1284. static CmeObject
  1285. GetEventEntry(Widget w, XEvent *event)
  1286. {
  1287.     Position x_loc = 0, y_loc = 0;
  1288.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1289.     CmeObject * entry;
  1290.     
  1291.     switch (event->type) {
  1292.     case MotionNotify:
  1293.     x_loc = event->xmotion.x;
  1294.     y_loc = event->xmotion.y;
  1295.     break;
  1296.     case EnterNotify:
  1297.     case LeaveNotify:
  1298.     x_loc = event->xcrossing.x;
  1299.     y_loc = event->xcrossing.y;
  1300.     break;
  1301.     case ButtonPress:
  1302.     case ButtonRelease:
  1303.     x_loc = event->xbutton.x;
  1304.     y_loc = event->xbutton.y;
  1305.     break;
  1306.     default:
  1307.     XtAppError(XtWidgetToApplicationContext(w),
  1308.            "Unknown event type in GetEventEntry().");
  1309.     break;
  1310.     }
  1311.     
  1312.     if ( (x_loc < 0) || (x_loc >= (int)cmw->core.width) || (y_loc < 0) ||
  1313.     (y_loc >= (int)cmw->core.height) )
  1314.     return(NULL);
  1315.     
  1316.     ForAllChildren(cmw, entry) {
  1317.     if (!XtIsManaged ((Widget) *entry)) continue;
  1318.  
  1319.     if ( ((*entry)->rectangle.y < y_loc) &&
  1320.             ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
  1321.         if ( *entry == cmw->complex_menu.label )
  1322.         return(NULL);    /* cannot select the label. */
  1323.         else
  1324.         return(*entry);
  1325.         }
  1326.     }
  1327.     
  1328.     return(NULL);
  1329. }
  1330.  
  1331. /*      Function Name: GetRightEntry
  1332.  *      Description: Gets an entry given a crossing event that has X and Y
  1333.  *                   coords, unless it exited to the right.
  1334.  *      Arguments: w - the complex menu widget.
  1335.  *                 event - the event.
  1336.  *      Returns: the entry that this point is in.
  1337.  */
  1338.  
  1339. static CmeObject
  1340. GetRightEntry(Widget w, XEvent *event)
  1341. {
  1342.     Position x_loc, y_loc;
  1343.     ComplexMenuWidget cmw = (ComplexMenuWidget) w;
  1344.     CmeObject * entry;
  1345.  
  1346.     x_loc = event->xcrossing.x;
  1347.     y_loc = event->xcrossing.y;
  1348.  
  1349.     if ( (x_loc < 0) || /*(x_loc < (int)cmw->core.width) ||*/ (y_loc < 0) ||
  1350.     (y_loc >= (int)cmw->core.height) )
  1351.     return(NULL);
  1352.  
  1353.     ForAllChildren(cmw, entry) {
  1354.     if (!XtIsManaged ((Widget) *entry)) continue;
  1355.  
  1356.     if ( ((*entry)->rectangle.y < y_loc) &&
  1357.             ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) ) {
  1358.         if ( *entry == cmw->complex_menu.label )
  1359.         return(NULL);    /* cannot select the label. */
  1360.         else
  1361.         return(*entry);
  1362.         }
  1363.     }
  1364.  
  1365.     return(NULL);
  1366. }
  1367.  
  1368. #endif /*]*/
  1369.